I fear not the man who has practiced 10,000 kicks once, but I fear the man who has practiced one kick 10,000 times。 Bruce Lee說過上面這句話,賣由翁也說了「我亦無他,惟手熟爾」。
對於初次接觸新知識或踏入新領域的人來說,無論多新手,都需要從基礎開始學習。勤奮可以彌補不足,但有系統、有組織的學習方式能夠事半功倍。(如果是大神前被發現內容有誤,還請批評指教orz)
期許筆者能有系統的分享,並和讀者一起受惠。
什麼時候會使用到 make
以及 new
?
目的是幫助 slice
、map
、 channel
分配記憶體並返回一個初始化的值。簡單來說就是返回已初始化得數據結構。 而且 只
用來分配
及初始化
型別為此三
的資料。
指定切片長度
。// 長度為 5,容量為 10 型別為 int 的 slice
s := make([]int, 5, 10)
a := make(型別, 指定切片長度, 指定預留的空間長度)
// 返回 string 和 int 的 map
m := make(map[string]int)
// 容量為 10 型別為 int 的 channel
ch := make(chan int, 10)
不會初始化內存,只會將內存清零。且 new
返回的是 pointer
,像是 *Type
。
舉例:
使用 new 分配一個新的 int
並初始化為零值(0),然後返回指向該整數的指針。
var p *int
p = new(int)
fmt.Println(*p)
// 輸出 0,因為整數的零值是 0
使用 new 分配一個新的 string
並初始化為零值(空string""),然後返回指向該 string
的指針 *
。
var strPtr *string
strPtr = new(string)
fmt.Println(*strPtr)
輸出空 string ""
使用 new 分配一個新的自定義 struct
,然後返回指向該對象的指針,該對象的字段將被初始化為各自類型的零值。
type Person struct {
Name string
Age int
}
var personPtr *Person
personPtr = new(Person)
fmt.Println(personPtr.Name) // 輸出空字符串,personPtr.Age
輸出 0
可以在分配後為指針指向的對象賦值。將整數指針指向的對象的值設置為 42
*p = 42
fmt.Println(*p)
輸出 42
設定自定義結構體的字段值。
personPtr.Name = "Alice"
personPtr.Age = 30
fmt.Println(personPtr.Name, personPtr.Age)
輸出 "Alice 30"
有時候零值並不足以滿足我們的需求,我們需要一個自定義的初始化函數(constructor)來為變數提供一個特定的初始狀態。同時,我們可以使用複合字面值(composite literals)來簡化對結構體或其他複雜類型的初始化。
舉例:
先初始化和建立 person 的 sruct 。後返回一個指向新創建函數的指針。
package main
type Person struct {
Name string
Age int
}
func NewPerson(name string, age int) *Person {
return &Person{
Name: name,
Age: age,
}
}
p := NewPerson("Alice", 30)
Array
是一種 固定大小
且 連續
的數據結構,用於存儲 相同類型
的元素。陣列的大小在宣告時就已經確定,且無法改變。
函數內對陣列的修改不會影響外部的陣列
。package main
import "fmt"
func main() {
// 宣告兩個不同大小的整數陣列
var arr1 [5] int
var arr2 [10] int
// 複製 arr1 到 arr2
arr2 = arr1
// 修改 arr2 的元素不會影響 arr1
arr2[0] = 100
// 輸出 arr1 和 arr2 的內容
fmt.Println("arr1:", arr1)
fmt.Println("arr2:", arr2)
}
會出現以下訊息,因為[5]int
和 [10]int
是不同的型別
,就像 int
和 float64
是不同的型別
一樣。無法將一個不同型別的值直接賦值給另一個不同型別的值。
cannot use arr1 (variable of type [5]int) as [10]int value in assignment
剛剛上面提過,Array
是 固定大小
且 連續
的數據結構,而 Slice
可以
在程式運行時增加
和縮小
。
Go 中較常使用的會是 Slice
array
的限制,可以在運行時增加或刪除元素。package main
import "fmt"
func main() {
// 創建一個整數陣列
arr := [5]int{1, 2, 3, 4, 5}
// 創建一個 Slice,包含陣列中的前三個元素
// Slice 由 arr[0:3] 表示,包含 0 到 2 的元素
slice := arr[0:3]
fmt.Println("原始陣列:", arr)
fmt.Println("Slice:", slice)
}
第二行第三個元素: 6
0 2 3
4 5 6
7 8 9
二維切片是切片的特殊形,它是一個 包含切片的切片
,通常用於表示二維數據結構,例如矩陣或表格。 看起來是 [][]
這樣。
package main
import "fmt"
func main() {
// 創建一個二維 slice
matrix := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
// 印出二維切片的值
fmt.Println("第二行第三個元素:", matrix[1][2])
// 修改元素的值
matrix[0][0] = 0
for _, row := range matrix {
for _, value := range row {
fmt.Print(value, " ")
}
fmt.Println()
}
}
第二行第三個元素: 6
0 2 3
4 5 6
7 8 9
key
快速存取 Element。key
應該是 唯一
的,否則找不到對應的 value
。key
和 Value
不需要匹配,可以不同。map[string][]int
key
應該是可比較類型。slice
、map
、function values
為不能比較的型別。map[int]bool
key
和 value
應該屬於同一類型。舉例:
func main() {
// 用前面提過的 make 建立一個 map。
scores := make(map[string]int)
// 加入 key 和 value。
scores["Alice"] = 95
scores["Bob"] = 88
// 使用 key (Alice)來呼叫 value (aliceScore) 。
aliceScore := scores["Alice"]
fmt.Println("1.Alice的分数是:", aliceScore)
// 可以使用 delete 刪除 key 和 value。
delete(scores, "Bob")
// 檢查 key 是否存在。
score, exists := scores["Charlie"]
if exists {
fmt.Println("2.Charlie的分数是:", score)
} else {
fmt.Println("3.Charlie不存在")
}
// 使用 for range 走訪 map 裡的 key 和 value。
for name, score := range scores {
fmt.Printf("4.%s的分数是:%d\n", name, score)
}
}
1.Alice的分数是: 95
3.Charlie不存在
4.Alice的分数是:95
在目標切面中要增加元素可以使用 append。
func append(slice []T, elements ...T) []T
// slice 目標切片,即要向其添加元素的切片。
// elements 是要添加到切片中的元素,可以是一個或多個。
package main
import (
"fmt"
)
func main() {
// 型別為 int 的 slice
slice := []int{1, 2, 3}
// 使用 append 向 slice 添加一個 element
slice = append(slice, 4)
// 添加多個 element
slice = append(slice, 5, 6, 7)
fmt.Println(slice)
}
[1 2 3 4 5 6 7]
今天做了 make
、new
; array
、slice
的簡單介紹與比較,還有聽起來有點陌生的 Constructors and composite literals
,也稍微提了 Map
、Printing
、Append
。
因為鐵人賽的緣故,讓我從新學過一遍,這又是另一種感覺,像極了最熟悉的陌生人。
(前言晚點寫